#include "GameManager.h"
#include "GameConst.h"
#include "Utils.h"
#include "Road.h"
#include "Moto.h"
#include "Bus.h"
#include "Car.h"
#include "VehicleInfo.h"
#include "Road.h"
#include "GamePlayLayer.h"

#include <string>
using namespace std;

#define TRIAL_TIME 604800				// second
#define ENCRYPT_KEY "Traffic"
#define FIRST_TIME_OPEN_KEY "fto"

GameManager* GameManager::instance = 0;

GameManager::GameManager()
{
}

bool GameManager::init(){

	srand (time(NULL));
	CCDirector::sharedDirector()->getScheduler()->scheduleUpdateForTarget(this,0,false);
	CCUserDefault* userDefault = CCUserDefault::sharedUserDefault();
    
    inputData = new InputData();
    bool isSuccess = false;
    string writeablePathString = CCFileUtils::sharedFileUtils()->getWritablePath();
    char* writeablePath = (char*)writeablePathString.c_str();
    char inputPath[1024];
    
    sprintf(inputPath, "%sLane1.txt", writeablePath);
    isSuccess = inputData->readAppendDataFromFile(inputPath);
    
    sprintf(inputPath, "%sLane2.txt", writeablePath);
    isSuccess = inputData->readAppendDataFromFile(inputPath);
    
    sprintf(inputPath, "%sLane3.txt", writeablePath);
    isSuccess = inputData->readAppendDataFromFile(inputPath);
    
    if(isSuccess == false) {
        char messageString[1024] = {0};
        sprintf(messageString, "Please copy Lane1.txt, Lane2.txt, Lane3.txt to below location, and restart application: %s", writeablePath);
        CCMessageBox(messageString, "Error");
    }
    char currentRunningDir[256];
    getcwd(currentRunningDir, sizeof(currentRunningDir));
    CCLog("Current running dir: %s", currentRunningDir);
    CCLog("Num data %d, min time %d", inputData->getVehicleDataArray()->count(), inputData->getMinStartTime());

	roadLength = userDefault->getFloatForKey(ROAD_LENGTH_KEY, 500*METTER_TO_POINT);
	laneWidth = userDefault->getFloatForKey(LANE_LENGTH_KEY, 3.5*METTER_TO_POINT);

//	motoWidth = userDefault->getFloatForKey(MOTO_WIDTH_KEY, Moto::width);
//	motoLength = userDefault->getFloatForKey(MOTO_LENGTH_KEY, Moto::length);
//	carWidth = userDefault->getFloatForKey(CAR_WIDTH_KEY, Car::width);
//	carLength = userDefault->getFloatForKey(CAR_LENGTH_KEY, Car::length);
//	busWidth = userDefault->getFloatForKey(BUS_WIDTH_KEY, Bus::width);
//	busLength = userDefault->getFloatForKey(BUS_LENGTH_KEY, Bus::length);

	greenLightTime = userDefault->getFloatForKey(GREEN_LIGHT_TIME_KEY, 60);
	redLightTime = userDefault->getFloatForKey(RED_LIGHT_TIME_KEY, 40);

	busLaneMode = userDefault->getFloatForKey(BUS_LANE_MODE_KEY, BLM_ALL);
	// end - stored value


//	addBusTime = 10;
//	addCarTime = 4;
//	addMotoTime = 2;
	preventCarTurnLaneBeforeCrossRoadDistance = 30*METTER_TO_POINT;

	safeDistanceAhead = 1*METTER_TO_POINT;
	safeDistanceBeside = 0.5*METTER_TO_POINT;

	vehicleInfoDictionary = CCDictionary::create();
	vehicleInfoDictionary->retain();

	currentVehicleId = 0;
	gamePlayLayer = 0;
//	sessionDuration = 0;
	gameTime = 0;

	// if this is first time use app
	isUseable = true;
    
    if(TRIAL_MODE){
        char firstTimeOpenKey[8];
        sprintf(firstTimeOpenKey, "%s%d", FIRST_TIME_OPEN_KEY, GAME_VERSION);
        
        time_t nowTime = time(0);
        int nowTimeD = nowTime;
        int firstTimeOpenEncrypted = CCUserDefault::sharedUserDefault()->getIntegerForKey(firstTimeOpenKey, -1);
        
        if(firstTimeOpenEncrypted == -1){
            int nowTimeDEncrypted = 0;
            xcrypt((char*)&nowTimeD, sizeof(int), (char*)&nowTimeDEncrypted, ENCRYPT_KEY);
            CCUserDefault::sharedUserDefault()->setDoubleForKey(firstTimeOpenKey, nowTimeDEncrypted);
        }
        else{
            int firstTimeOpen = 0;
            xcrypt((char*)&firstTimeOpenEncrypted, sizeof(int), (char*)&firstTimeOpen, ENCRYPT_KEY);
            int duration = nowTimeD - firstTimeOpen;
            if(duration > TRIAL_TIME)
                isUseable = false;
        }
    }

	vehicleInfoFile = 0;
	road = 0;
	oneSecondTimer = new CCTimer;
	oneSecondTimer->initWithTarget(this, schedule_selector(GameManager::oneSecondTick), 1, 0, 0);

	resetGame();

	return true;
}

GameManager::~GameManager()
{
	DELETE_SAFELY(instance);
	vehicleInfoDictionary->release();
}

GameManager* GameManager::getInstance(){
	if(instance == 0){
		instance = GameManager::create();
		instance->retain();
	}
	return instance;
}

int GameManager::getCurrentVehicleId(){
	currentVehicleId++;
	return currentVehicleId;
}

void GameManager::resetGame(){
	currentVehicleId = 0;
	vehicleInfoDictionary->removeAllObjects();
	beginNewSession();

	numBusLane1 = numCarLane1 = numMotoLane1 = numCarLane2 = numMotoLane2 = numCarLane3 = numMotoLane3 = 0;
	road = 0;
	gameTime = inputData->getMinStartTime();

//	Moto::length = motoLength;
//	Moto::width = motoWidth;

	Car::length = carLength;
	Car::width = carWidth;

	Bus::length = busLength;
	Bus::width = busWidth;
//	Bus::vMax = vBusMax;
}

void GameManager::beginNewSession(){
	strcpy(currentSessionTimeString, getCurrentTimeStringForFileName());
	string writeablePathString = CCFileUtils::sharedFileUtils()->getWritablePath();
	char* writeablePath = (char*)writeablePathString.c_str();
	
	char filePath[256] = {0};
	strcat(filePath, writeablePath);
	strcat(filePath, currentSessionTimeString);
	strcat(filePath, "-VehicleInfo");
	sprintf(filePath,"%s%s", filePath, ".txt" );

	CCLog("Vehicle info file path : %s", filePath);

	if(vehicleInfoFile){
		fclose(vehicleInfoFile);
		vehicleInfoFile = 0;
	}
	vehicleInfoFile = fopen(filePath, "wb");

	char tempString[32];
	sprintf(tempString, "Time: %s\r\n\r\n", currentSessionTimeString);
	fwrite(tempString, strlen(tempString), 1, vehicleInfoFile);
}

void GameManager::endSaveSession(){
    if (vehicleInfoDictionary->count() == 0) {
        return;
    }
    
	if(vehicleInfoFile){
		fclose(vehicleInfoFile);
		vehicleInfoFile = 0;
	}

	saveLaneInfo();

	string writeablePathString = CCFileUtils::sharedFileUtils()->getWritablePath();
	char* writeablePath = (char*)writeablePathString.c_str();

	char filePath[128] = {0};
	strcat(filePath, writeablePath);
	strcat(filePath, currentSessionTimeString);
	strcat(filePath, "....txt");

	char messageString[1024] = {0};
	sprintf(messageString, "Output saved file location: %s", filePath);
	CCMessageBox(messageString, "Information");
}

void GameManager::saveVehicleInfo(){
	CCArray* vehicles = road->getVehicles();
	if(vehicles->count() < 1)
		return;

	char infoString[128000] = {0};
	strcpy (infoString, "\r\n");
	

	char vehicleTypeString[8] = {0};
	char tempString[128] = {0};
	char currentTimeString[32];

	sprintf(tempString, "Number vehicles: %d\r\n", vehicles->count());
	strcat(infoString, tempString);

	CCObject* obj;
	CCARRAY_FOREACH(vehicles, obj){
		Vehicle* vehicle = (Vehicle*)obj;

		switch (vehicle->getTag())
		{
		case ID_SMALL_MOTO:
			strcpy(vehicleTypeString, "mot");
			break;
		case ID_CAR:
			strcpy(vehicleTypeString, "car");
			break;
		case ID_BUS:
			strcpy(vehicleTypeString, "bus");
			break;
        case ID_TRUCK:
            strcpy(vehicleTypeString, "truck");
            break;
        case ID_BIG_MOTO:
            strcpy(vehicleTypeString, "bigmot");
                break;
		}

		strcpy(currentTimeString, getCurrentTimeString());
		sprintf(tempString, "%s: id %d, type %s, velocity = %f(m/s), position (%f, %f), lane %d, times turn lane %d\r\n", currentTimeString, vehicle->getVehicleId(), vehicleTypeString, vehicle->getV().x*POINT_TO_METTER, vehicle->getPositionX()*POINT_TO_METTER, vehicle->getPositionY()*POINT_TO_METTER, road->getWhichLane(vehicle), vehicle->getNumTurn());
		strcat(infoString, tempString);
	}

	int size = strlen(infoString);
	CCLog("Size string saveVehicleInfo: %d", size);
	fwrite(infoString, size, 1, vehicleInfoFile);
}

void GameManager::oneSecondTick(float t){
	if(road && vehicleInfoFile)
		saveVehicleInfo();
}

void GameManager::update(float delta){
	if(delta > TIME_NOT_UPDATE)
		return;
	oneSecondTimer->update(delta);
}

void GameManager::saveLaneInfo(){
	char infoString[1024] = {0};
	char tempString[128] = {0};

	sprintf(tempString, "Time: %s\r\n\r\n", currentSessionTimeString);
	strcat(infoString, tempString);

	sprintf(tempString, "Total numbers of vehicle: %d\r\n\r\n", vehicleInfoDictionary->count());
	strcat(infoString, tempString);

	strcat(infoString, "Lane -- Number bus -- Number car -- Number motor\r\n");
	sprintf(tempString, "1. %d -- %d -- %d\r\n", numBusLane1, numCarLane1, numMotoLane1);
	strcat(infoString, tempString);
	sprintf(tempString, "2. %d -- %d -- %d\r\n", 0, numCarLane2, numMotoLane2);
	strcat(infoString, tempString);
	sprintf(tempString, "3. %d -- %d -- %d\r\n", 0, numCarLane3, numMotoLane3);
	strcat(infoString, tempString);

	string writeablePathString = CCFileUtils::sharedFileUtils()->getWritablePath();
	char* writeablePath = (char*)writeablePathString.c_str();

	char filePath[128] = {0};
	strcat(filePath, writeablePath);
	strcat(filePath, currentSessionTimeString);
	strcat(filePath, "-LaneInfo");
	strcat(filePath, ".txt");

	int size = strlen(infoString);
	FILE* file = fopen(filePath, "wb");
	if(file){
		fwrite(infoString, size, 1, file);
		fclose(file);
	}
}

void GameManager::increaseGameTime() {
    gameTime++;
    CCNotificationCenter::sharedNotificationCenter()->postNotification(kGameTimeIncreaseNotification);
}

int GameManager::getGameTime() {
    return gameTime;
}